package com.study.spmongodb.book.wwj.char05;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;

/**
 * @author MI
 * @version 1.0
 * @date 2020/11/25 21:06
 */
public class BooleanLock implements Lock {

    private Thread currentThread;
    private boolean locked = false;
    private final List<Thread> blockedList = new ArrayList<>();

    @Override
    public void lock() throws InterruptedException {
        synchronized (this) {

            //如果当前锁已经被某个线程获得，则该线程将加入阻塞队列并且使用当前线程wait释放对this monitor的所有权
            while (locked) {
                blockedList.add(Thread.currentThread());
                this.wait();
            }

            //如果当前锁没有被其他线程获得，则该线程将尝试从阻塞队列中删除自己（如果当前线程从未进入过阻塞队列，删除方法不会有任何影响），
            blockedList.remove(Thread.currentThread());
            this.locked = true;
            this.currentThread = Thread.currentThread();

        }

    }

    @Override
    public void lock(long mills) throws InterruptedException, TimeoutException {
        synchronized (this) {
            if (mills < 0) {
                this.lock();
            } else {
                long reaminingMills = mills;
                final long endMills = System.currentTimeMillis() + reaminingMills;
                while (locked) {
                    if (reaminingMills <= 0) {
                        throw new TimeoutException("can not get the lock during");
                    }
                    if (!blockedList.contains(Thread.currentThread())) {
                        blockedList.add(Thread.currentThread());
                    }
                    this.wait(reaminingMills);
                    reaminingMills = endMills - System.currentTimeMillis();
                }
                blockedList.remove(Thread.currentThread());
                this.locked = true;
                this.currentThread = Thread.currentThread();
            }
        }

    }

    @Override
    public void unlock() {

    }

    @Override
    public List<Thread> getBlockedThreads() {
        return null;
    }
}
